Welcome back.
In this lecture we're going to be learning about instance streaming, which is an awesome feature that
allows us to dynamically load and unload 3D content in the workspace of our game.
Enabling instant streaming can help to improve join times, improve memory usage, improve performance,
and enables some level of detail features to optimize distant models and terrain.
Instance streaming is a must have for any game, with large maps as reducing join times and improving
memory usage and performance is important for good user experience in your games.
Instance streaming is going to be enabled by default on every new game that you create in Roblox.
So if you go to the workspace and if you scroll down in your properties menu, you should see this streaming
section and streaming enabled will be checked by default.
And if we uncheck it, then we'll disable streaming.
And the difference between streaming and streaming disabled.
If a player joins your game, if streaming is disabled, then all of the parts inside of the workspace,
all of the models, all of the descendants will be replicated right when the player joins, and then
the game loaded event will fire after all of those instances have loaded for that particular player.
However, if you have streaming turned on, then what's going to happen is that only models and parts
that are within a certain radius of the replication focus for a player are going to be loaded, while
everything else, all the other base parts in your game are going to be ignored.
This is how we can improve performance, memory usage, and join times for your game.
And that's by not loading everything in the game all at once.
Now we're going to learn about all of these different properties inside of streaming enabled, and we're
also going to take a look at some additional properties for models that show up when you enable streaming.
So there is this property called Model streaming mode for all of the models in your game when you have
instant streaming turned on.
But when you turn this off and you go and check your model, as you can see, that property is no longer
there.
So the first property we're going to take a look at for streaming enabled is going to be the Streaming
Integrity mode.
Now, the streaming integrity mode by default is going to be set to disabled.
And disabled means that the game is not going to pause, or the client is not going to pause simulation
for any reason whatsoever.
However, these two other options, which is minimum radius, pause and pause outside of the loaded
area, are a little bit different.
So with minimum radius pores, what's going to happen is that if any instance, such as a model or a
part in the game reaches within the minimum radius around the player and it's not streamed in, then
the player is going to have their game paused.
And then with pause outside of loaded area.
This one's a little bit different.
Where simulation around the replication of focus property of our player is going to be paused when the
replication focus instances bounding box is not inside of a streamed area.
What do I mean by this?
Well, every single player in your game has a property called replication Focus.
By default, the replication focus property is going to be the primary part of your player's character,
which is your humanoid root part.
However, the server can manually set the replication focus to be a different part in the workspace,
and this part has a bounding box.
For example, this part right here has a volume, and this volume right?
The border of this volume is considered its bounding box.
So whenever you have your replication focus bounding box, enter into an area that has not been streamed
in.
Then the area around that replication focus part is going to be paused, simulation is going to be paused,
and we're going to take a look at this behavior in a moment.
So if I were to have streaming enabled, turned off and I would go to play my game.
As you can see, all of the parts in my workspace and even this model that's far away from me are all
loaded in.
I have access to all of the instances within my workspace, just as I would expect without having streaming
enabled.
However, if I were to go and enable streaming.
And I'll just keep this at the default settings for now.
So let me move this back to defaults.
Keep all these on the default.
And then our to go and play my game.
As you can see right away, I am missing a ton of these parts.
I only have a certain chunk of these parts loaded.
I don't have that model loaded, and I certainly don't have the rest of those parts loaded.
And if I go ahead and take a look at my workspace, as you can see, there's not as many parts inside
of this folder that I should have.
And this model that was supposed to be off in the distance has no descendants inside of it.
So this is what Streaming Enabled does.
When I go and start walking around, it will start loading.
In these instances, as you can see, more are appearing in my folder.
And if I were to go walk to where my model is, which is down over here.
And as you can see, more of these parts are loading in.
Eventually, there we go.
I hit my model right here.
And as you can see now, this model has these base part children that have streamed in to my player.
Now these parts are streaming in around me based on these two properties right here streaming minimum
radius and streaming target radius.
You can basically think of these as two circular zones around the player, where parts and models are
streamed in at different priorities.
So with streaming minimum radius, this is a circular zone around your player, where parts of models
are going to be streamed in at the absolute highest priority.
Whereas the streaming target radius is going to be a zone around the player, where the server is going
to be much more relaxed when trying to stream objects to our player.
Now these two values are going to influence heavily your streaming integrity mode when you don't have
it set to disable.
So you have two of these different properties and minimum radius pause and pause outside loaded area.
Now remember minimum radius pause.
What's going to happen is that the client is going to pause their game.
When any instances that are not streamed in enter into our minimum radius.
So it's going to pause the game, and it's going to wait until those instances get streamed in.
And then it's going to unpause the game.
To better visualize this, I've created these two circles.
You can imagine the black dot as our player.
You can imagine the red circle as the minimum radius, and you can imagine the blue circle as the target
radius.
So when we have objects in our game, for example, if we have like models outside here, these models
are not going to be streamed in for our player because they are not within the target radius or the
minimum radius.
However, once one of these models gets within our target radius, then the server is going to be like,
okay, I should try to replicate this part or this model to my player as soon as possible, but I'm
not going to be that urgent about it because it's only within the target radius.
However, if this model gets to this minimum radius and it hasn't been streamed in yet, so if it gets
in there, then the server is going to be like, whoa, the player has not loaded this part in.
And if we have um, minimum radius pause enabled, then this player is going to pause their game.
The server at the highest priority is going to try to replicate this model apart to our player.
And once it does that then the player can unpause their game.
So that means it's very important to keep a sizable gap between these two radiuses.
And that's because if the radius of our target radius was the same as the minimum radius, then we have
literally zero opportunity for the server to load in parts between those two zones.
Instead, these parts or models are going to instantly hit the minimum radius, and our player is going
to keep pausing the game over and over and over again.
And that's going to be a big problem for user experience.
So to show minimum radius, pause and action, what I'm going to do is I'm going to duplicate this parts
folder a lot.
So I'm just going to duplicate it and then duplicate it a bit more and duplicate it again.
So there's a lot of stuff that the player would have to stream in over here.
And then we can go ahead and pick one of these random parts.
Preferably I'll do one in the middle, like I'll pick this one and I'm going to copy the position of
this part.
And then we can go and play our game.
And.
If you see here.
As you can see, we only have these parts streamed in and we don't see any of those parts streamed in
all the way out there.
But if we go ahead and take a look at the server, as you can see, the server has access to all of
these instances in our game.
And as you can see, our player is right here.
But as you saw earlier, our player can only see these particular parts.
Now, if I were to update the position of my part to that position I copied, you're going to see the
game pause for a split second as the server tries to stream all of these instances to the player.
So if I hit enter.
As you can see, that was pretty quick, but there was a little pop up where the game paused simulation
until we were able to stream all of these other instances in.
Now, because we're running this on a local server, obviously all of these objects replicate into the
player is going to be really fast, but in an actual server setting, this is going to be much slower.
So the player is going to have their game paused for a longer period of time.
Now to show the problem.
When our target radius is the same as our minimum radius, we're going to set it to 64, the exact same
as our minimum radius.
And we're going to play test the game.
And while our player walks around and starts loading in these parts, as you can see, the game is going
to start freezing or pausing itself because these instances are hitting the minimum radius and they
haven't loaded in yet.
So the client's going to freak out and be like, oh, we haven't loaded them in yet.
Let's go ahead and pause the game.
So when I start walking, as you can see, we're getting these pop ups of game play paused, game play
paused.
And if you had a lot of parts and models in your game, this would obviously be pausing for a lot longer,
and it would just completely ruin the user experience, because every time the player walks around,
they have to keep pausing the game.
And that's just stupid.
So you always want to make sure that your streaming target radius is at least double of what your minimum
radius is.
And since the smallest number you can set for the minimum radius is 64, then that means your streaming
target radius should at least be 128 studs.
So that's double the minimum radius.
And now if we go and playtest our game.
When our player goes and walks around.
As you can see, we are no longer pausing anymore.
We're loading in these objects.
The game is not freezing, and even if I go walk over here and load in this part or this model, because
this model entered into the target radius, it had a chance to replicate to our player before it hit
the minimum radius.
And that's very important.
So whenever you have minimum radius pores enabled, you want to make sure that your target radius is
at least double your minimum radius.
That way you're giving these parts and these models an opportunity to stream in to the client before
the client, you know, pauses the game because it hit the minimum radius.
Now this other option is going to be called pause outside loaded area.
And what's going to happen with this one, if you remember earlier, is that simulation is going to
be paused around a replication focus.
If we look here in the Roblox documentation, as you can see, every single player in our game has a
property called Replication Focus, and it says the Replication Focus player property sets the part
to focus replication around a player.
Different Roblox systems that communicate over the network, like physics, replicate at different rates,
depending on how close objects are to the replication focus.
When this property is nil, it reverts to its default behavior, which is to treat the local player's
characters primary part as the replication focus.
So that would be your humanoid root part.
You set this property with a server script and not a local script.
So to demonstrate this replication focus property, what we're going to do is we're going to set up
a one player server in the test tab.
So that way we can visualize both the client and the server at the same time.
And what I'm going to do here for my player is I'm going to take one of these parts.
I'm going to duplicate it.
And I'm going to go to my properties panel just to make sure that it is collidable, and I'll un anchor
it.
So that way my player has network ownership over this part.
And because I have network ownership here on the client, that means if I move it around on the client,
we should be able to see that movement on the server.
So.
It's actually not moving, which is kind of interesting.
Did I anchor it?
I did un anchor it.
Give me network ownership.
So let me try moving again.
Okay, there we go.
Now I have a network ownership over this part, which means when I move it, the server observes those
changes when I move it around.
So now, because I have network ownership over this part, I want to change the replication focus for
my player to be set to this part.
So I'm going to take this part, and I'm going to set its parent equal to the workspace.
So that way I can reference it easier.
And we're going to do is we're going to get the player service and get player one, and we're going
to update the replication focus property equal to workspace dot part.
And then if we go ahead and hit enter, we executed this code in our command line.
And now this part should be my new replication focus.
So if I zoom out here and if I go to try to load the parts that are over here and I move this part around,
as you can see now, this part is acting as my replication focus instead of my player.
So even if my player here.
If I were to walk away.
Actually, I can't walk.
So as you can see, all this stuff outside of my replication focus has simulation pores.
So even though I'm trying to walk around, I can't.
I will only be able to walk around as soon as this part comes close enough again.
And now I am able to walk around.
So as you can see, when we have it set to the pores outside of loaded area, when I move this replication
focus far enough away.
Now I am unable to move my character around.
That's because simulation for my character has stopped, because we're set on the pause outside of the
loaded area property, and this part is acting as my replication focus.
So it isn't until this replication focus comes close enough that I'm able to move my character again,
but let me have my character walk far enough away.
So that way we definitely know that my player is not streaming in this model over here.
And if I go and move my part over there, as you can see, my part has now loaded in this model.
And that's because the server is treating this part as the replication focus for my player.
Now, since the game is only going to pause when the bounding box of this replication focus enters into
an area that has not streamed in.
That means if we hit an area very quickly where we have not loaded any stuff in, then the game is going
to pause because again, this replication focus will be in an area where stuff has not loaded in.
So for example, if you were to teleport the player somewhere and you had it set to pause outside of
loaded area, well that means the player is now going to be in in an area that has not been streamed
in.
So the game is going to pause.
The next property we're going to take a look at here is called streaming Out Behavior.
And this property determines how instances should stream out in our game.
The default is set to low memory and low memory.
What this basically does is that it will stream in all of these parts or objects in our game, and it
won't stream them out until the game recognizes that the computer or our device is running low on memory.
So once it starts running low on memory, then the game will start streaming out stuff that is farthest
away from us until it's satisfied with how much memory we have left.
The other option is called opportunistic.
And what, this, uh, what this property does is that any instances that exit outside of our target
radius will be immediately streamed out, and then any instances that reach into our target radius will
obviously be streamed in.
So if you have any model or part that get outside of our target radius for our players replication focus,
then they're going to immediately stream out.
So let's go ahead and take a look at this.
If we go and playtest the game.
And if we just, let's say we start walking this way.
These parts should start to slowly disappear.
So I'm walking, I'm walking, I'm walking.
There we go.
And now these parts are beginning to unload as I get farther and farther away from them.
And that's what the opportunistic mode does.
Once these parts get outside of my target radius, they stream out, and then once they come back into
my target radius.
Then they'll start to stream back in.
Just like that.
Alrighty, the next part of instant streaming we're going to take a look at is this model streaming
mode property that appears for all of the models in our game when we have instant streaming enabled.
Now, this property determines how a model is going to be streamed in or streamed out.
The default is set to something called Non-atomic.
And what Non-atomic means is that the children of a model will be streamed in or streamed out when they
are within range, but any children within the model that are not 3D objects will not be streamed out.
So when we have a model set to Non-atomic, that means the model itself will appear in our game.
But any base part descendants that are not within range of our player will not be streamed in.
So that means we will only see this model instance and none of the descendants until we get close enough
to stream these base parts in.
If this model had other children, for example, like a script, then the model and the script would
be streamed in immediately for our player when they join the game on Non-atomic.
But any of these base parts would not be streamed in until we got close enough where they hit our target
radius.
Now, atomic is the complete opposite.
What atomic does is that it streams in the entire model when we get close enough to the model.
So when the player joins the game, any models that are atomic and they aren't within range of the player
will not be streamed in, even if they have, uh, descendants that aren't base parts.
So the entire model won't appear in our game.
But as soon as we get close enough to stream the model in, we hit one of these, uh, parts that are
inside of the model.
Then the entire model as a whole will stream into the game, and then when we get far enough away from
it, then the entire model as a whole will stream out.
So that's the difference between atomic and non-atomic.
So let's first go ahead and take a look at Non-atomic.
And we'll playtest our game.
And if I go and walk towards the area where my model is, and actually before I do that, if we look
in the workspace, as you can see, here is our model and we can see the script, which is a child of
our model, but we don't see any of the base parts.
It isn't until we get close enough where those parts have hit our target radius, where now we have
streamed them in, and then when we walk away.
Those parts when they leave are going to be streamed out just like that.
However, our model and the script inside of our model, or any descendants in the model that aren't
um, base parts will be left inside of here.
Now, there is exceptions to this.
For example, if parts in the model have children of their own, those will also be streamed out because
they are children of those base parts.
But any, uh, other descendants or children of this model that aren't parented to any base parts,
they're going to remain inside of my model.
However, once I swap this mode to atomic and then we were to go and play the game when we take a look
at our workspace, as you can see, we can no longer see the model anymore, right?
If we go and walk towards the direction where our model is.
Now the entire model streams in together, including the script and all of the descendants.
And then when we go and walk away.
The entire model should stream out.
And there we go.
We no longer see that model anymore.
The other mode here is going to be called persistent.
And what persistent means is that this model will immediately stream in when the player joins the game.
No exceptions.
So even if the player is not within range of this model, this model is going to be streamed in when
the player joins.
And this model is never going to be streamed out even if the player gets far enough away.
So if I go and play test my game with a persistent model, as you can see, I see my model over there.
And even if I were to walk really far away from my model.
It is never going to stream out because we have it set to persistent.
It will stay in our game forever.
The last option we have here for our model is called persistent per player.
Now this property works the exact same as atomic, but we can actually go out and pick which players
in our game.
We would like to have this model be persistently streamed for.
So what I mean is that if we don't choose any players to be persistent for this model, then this model
is just going to act as an atomic model for those players.
However, if we pick a particular player in our game, let's say a player joins a game and we go throughout
the map and pick certain persistent per player models to be always on the map for those particular players,
then it's going to act as a persistent model.
So to demonstrate this, we can set up a two player server instead.
And here I have my two player setup.
And as you can see, both of these players cannot see that model because it's currently acting as atomic.
And that's because the server has not set for that particular model for a player to be persistent.
Now, if I look on the server here, what I can go ahead and do is I can go ahead and pick one of these
players to be persistent with this model.
So what I can do is I can refer to the model in my workspace.
It would be workspace dot model.
And then we have a function which is add persistent player.
And it says sets this model to be persistent for the specified player.
So now we can go ahead and specify player.
For example we could do player one.
So I'll pass game dot players dot player one and then we'll hit enter.
And now we have added player one to be persistent for this particular model.
So if we go ahead and take a look at our game again with both of our players, as you can see now player
one has loaded this model in because it's supposed to be persistent for us.
But player two has not loaded the model in.
I have to go and walk over here and actually stream in the model just like that to be able to see it.
But then if I walk away from the model.
The model is going to stream back out again for me just like that.
And that's because player two is not set to be persistent with this model.
However, player one, on the other hand, can walk away as far as he'd like and that model is going
to remain visible for him, even if he's like a thousand studs away, it's always going to be there.
So that is all of the different model streaming mode properties for models.
However, there is one last property we need to look at within the workspace that actually affects this
model streaming mode property.
And that property is called model streaming behavior.
And there's two different ones.
There's one which is called legacy, which is the default.
And there's another one here called improved.
What's the difference between those two?
Well, what improved does is that it takes non-atomic models and it only replicates those models when
one of the base part descendants are within range to be streamed.
So basically, in other words, if we have a model in our game like this one over here, and our player
is not within range of any of the descendant based parts of this model, then the entire model itself
will not be streamed into the game, even if it's set to atomic.
That's because the improved mode for model streaming behavior basically forces all of the models in
your game to respect this new property, where if the player is not within range of any of the descendant
based parts of a model, then the entire model is going to be streamed out.
Once the player actually gets within range of one of the base parts of the model, then it will stream
the entire model in together.
So even if your model was set to Nonatomic, where it would typically keep the model itself in the improved
mode for model streaming behavior is not going to respect this property, and it's not going to stream
this model to the player unless the player is within the range of one of these base parts.
Now, the legacy mode, which we were on by default, allows us to control it through these different
model streaming mode properties where any Non-atomic models and any non base part children of the model
are going to be replicated when the player joins, regardless if that model is within range or not,
and then any eligible children based parts of that model are going to be streamed in when the player
is in range.
So this model streaming behavior mainly affects the Nonatomic property for model streaming mode.
So when we have it set to legacy, that means this model is going to stream in the model itself and
the script.
But if these base parts aren't in range, then it's not going to stream these base parts in.
And then if we have it set to improved, then this entire model itself will not be streamed in and it
will only stream in once the player is within range one of these base parts.
So let's actually go ahead and take a look at that.
We're going to keep our model at Nonatomic.
And then we're going to go ahead and set it to improved.
And then we can go ahead and playtest our game.
And if we go ahead and take a look in the workspace, as you can see, our model does not exist within
the workspace.
It isn't until we get within range of one of those bass parts where the entire model becomes streamed
in, and then when we go and walk away, the entire model is going to be streamed out because we are
no longer within range of any of those bass parts.
So just like that, even though that model is set to non-atomic, it is acting as an atomic model.
And that's because we have set the model streaming behavior to be improved.
Now, if we go ahead and swap model streaming behavior back to legacy or the default, and we go and
play test the game.
And we were to check the workspace.
As you can see, we do see our model here, and we do see the script inside of it.
And then any eligible base parts within our model are going to be streamed in once we get in range.
So as you can see, all of the base parts pop in.
And then when we walk away.
All of the base parts should disappear just like that, but the entire model itself does not get streamed
in or streamed out.
It stays within our workspace.
Now, there is one other thing to mention with the improved model streaming behavior, and that's if
you have a model that contains nothing but non bass part children.
So if this model contained a humanoid and a script and some other non bass part stuff like a screen
guy or whatever the case may be, then this model is the exception to this improved model streaming
behavior.
Because this model does not have any bass part children, then the game doesn't need to have to worry
about whether or not the player is within range of any bass part children, because it doesn't have
any.
So that means once our player joins the game, it will replicate this entire model to our player, and
it will also never stream it out.
So if we go and play test the game and we look in the workspace, as you can see, our model that doesn't
have any bass part children has replicated to us even while we are on the improved model streaming behavior.
So the improved model streaming behavior acts a little bit differently.
If a model has bass part children or if it doesn't.
Now, the very last thing we're going to take a look at, for instance, streaming is another property
in our model called Level of Detail.
An automatic is set to disabled.
So that's the default.
But we have another option here called streaming Mesh.
And what this streaming mesh property does is that any models in your game that have this streaming
mesh property enabled, what it's what's going to happen is when you publish your game, Roblox is going
to create a mesh that's basically going to wrap over all of the instances or base parts within your
model.
And then when your player gets far enough away from your model where the model streams out in its place,
it's going to set this what they call an impostor mesh, so it doesn't look like the part has unloaded,
even though it has.
And the streaming mesh level of detail property is very useful for big maps.
Let's say you had a city and a very big map, and when the player got far enough away from the city,
you didn't want to unload that entire city.
But you would.
You would rather keep that city far away, but still visible but not loaded to the player.
Well, that's where you would use a streaming mesh, because once the player gets far enough away from
the city and the server, uh, streams out the city from the player, it's going to put an impostor
mesh in place of those city buildings.
So because I have it set to streaming mesh here, you're going to see what I mean when I play test my
game.
If I go ahead and look behind me, as you can see, that's not actually my model over there.
That is actually an impostor mesh.
So even though we can see our model right here, there is no base part children.
There is an imposter that has basically wrapped over where our parts would actually be.
But then once I actually go and walk over to my model, it's going to get rid of that impostor mesh.
And there we go.
Now the real base parts have loaded in, but then when I walk away from it.
You're going to see the bass parts disappear.
And then in its place is an imposter mesh.
Now, something important to note is that impostor meshes will still take up network data.
So if I go and view on the client here and I open up my network information and we take a look at the
overall incoming data, and even though this client doesn't have that model loaded in, it's just the
impostor mesh.
If I were to start moving around this model on the server, it's also going to start moving that impostor
mesh around.
So if I move it over here, as you can see, the client can also see the model moving, even though
our player doesn't actually have those bass parts loaded in, and instead it is moving the impostor
mesh along with, uh, the model that is being moved on the server.
So as you can see, our overall incoming data is still increasing even though none of the bass parts
are loaded in.
And that's because we have set an imposter mesh in the place of the actual parts in the model.
However, this imposter mesh does not dynamically update.
So if I were to start changing the size and shape and position of these parts inside of the model,
you can see that my impostor mesh is not changing.
If I go and walk over to where my model is at, you're going to see the imposter mesh disappear.
And then there's my actual real bass parts.
And then when I go and walk away and unload those bass parts again.
As you can see, the imposter mesh has now taken place over the parts in my model.
So that's just something important to note, is that streaming messages do not dynamically update during
runtime, and you also cannot create streaming messages during the runtime of your game.
Streaming meshes are only created when you publish the game.
So even if I were to like, for example, create a new part on the server, actually let me anchor this
part.
Let me open up my properties panel, anchor that.
So even if I were to create this new part, put it inside of a model.
Let me change the size real quick.
Do something like that.
Even if I were to set this to streaming mesh, as you can see, the player doesn't see any mesh.
And that's because these impostor meshes are only created when your game is published.
However, if we were to duplicate this model, since this model already has a streaming mesh attached
to it, if I duplicate it and then move it.
As you can see, my player gets to see that other impostor mesh and I can duplicate this multiple times.
So I have three separate different impostor meshes.
And if I go and walk over the real models.
There you go.
We'll load in and then that other model loaded in as well.
But this other model that was created during the runtime of my game, even though we set it to have
a streaming mesh, streaming meshes are not created at runtime, so there's no point in doing that.
Hopefully you now have a better understanding of instant streaming and how you can utilize this awesome
feature in your games.
That is the entirety of instant streaming for now.
They might update it and add more features in the future, but that is the complete extent of instant
streaming.
You have these properties here, and you have two properties in parts where you're able to control and
manipulate how models and bass parts stream in and out of your game.
That's all I have for you in this lecture, and I will see you in the next one.